#include "ASMessage.h"
#include "ASEntity.h"
#include "utils.h"

NS_AS_BEGIN



ASMessage::ASMessage(const char* MsgID,ASEntity* pSender,ASEntity* pReceiver,float fDelayTime,int nExtraData,void* pExtraInfo):
	_pSender(pSender),
	_pReceiver(pReceiver),
	_MsgID(MsgID),
	_fDelayTime(fDelayTime),
	_pExtraInfo(pExtraInfo),
	_nHandleCount(0),
	_bActive(true)
{
	_MsgIDHash = AS_StrHash(MsgID);
#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RETAIN(_pSender);
	AS_SAFE_RETAIN(_pReceiver);
#endif
}

ASMessage::~ASMessage()
{
#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RELEASE(_pSender);
	AS_SAFE_RELEASE(_pReceiver);
#endif
}


ASMessage::ASMessage(const ASMessage& copy):
	_pSender(copy._pSender),
	_pReceiver(copy._pReceiver),
	_MsgID(copy._MsgID),
	_MsgIDHash(copy._MsgIDHash),
	_fDelayTime(copy._fDelayTime),
	_pExtraInfo(copy._pExtraInfo),
	_nHandleCount(0),
	_bActive(true)
{
	#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RETAIN(_pSender);
	AS_SAFE_RETAIN(_pReceiver);
	#endif
}
ASMessage& ASMessage::operator=(const ASMessage& copy)
{
	#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RELEASE(_pSender);
	AS_SAFE_RELEASE(_pReceiver);
	#endif
	_pSender=copy._pSender;
	_pReceiver=copy._pReceiver;
	_MsgID=copy._MsgID;
	_MsgIDHash=copy._MsgIDHash;
	_fDelayTime=copy._fDelayTime;
	_pExtraInfo=copy._pExtraInfo;
	_nHandleCount=copy._nHandleCount;
	_bActive=copy._bActive;
	#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RETAIN(_pSender);
	AS_SAFE_RETAIN(_pReceiver);
	#endif
	return *this;
}


ASMessageObserver::ASMessageObserver(ASEntity *pReceiver, const char* MsgID, SEL_CallFuncD callfunc):
	_pReceiver(pReceiver),
	_MsgID(MsgID),
	_bActive(true)
{
	ASAssert(pReceiver!=nullptr,"ASMessageObserver pReceiver is NULL");
	if (callfunc)
	{
		_callfunc = callfunc;
	}
	else
	{
		_callfunc = ascallfuncD_selector(ASEntity::onHandleMessage);
	}
	
	_MsgIDHash = AS_StrHash(MsgID);
#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RETAIN(_pReceiver);
#endif
}

ASMessageObserver::~ASMessageObserver()
{
#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RELEASE(_pReceiver);
#endif
}

ASMessageObserver::ASMessageObserver(const ASMessageObserver& copy):
	_pReceiver(copy._pReceiver),
	_callfunc(copy._callfunc),
	_MsgID(copy._MsgID),
	_MsgIDHash(copy._MsgIDHash),
	_bActive(true)
{
	#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RETAIN(_pReceiver);
	#endif
}
ASMessageObserver& ASMessageObserver::operator=(const ASMessageObserver& copy)
{
	#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RELEASE(_pReceiver);
	#endif
	_pReceiver=copy._pReceiver;
	_callfunc=copy._callfunc;
	_MsgID=copy._MsgID;
	_MsgIDHash=copy._MsgIDHash;
	_bActive=copy._bActive;
	#ifdef ASOBJ_REFCOUNT
	AS_SAFE_RETAIN(_pReceiver);
	#endif
	return *this;
}


void ASMessageObserver::onHandleMessage(void *data)
{
	if (_pReceiver&&_callfunc&&_bActive)
    {
		(_pReceiver->*_callfunc)(data);
    }
}

bool ASMessageObserver::operator==(const ASMessageObserver& rhs)const
{
	return (_pReceiver==rhs._pReceiver&&_callfunc==rhs._callfunc&&_MsgIDHash==rhs._MsgIDHash&&_MsgID==rhs._MsgID);
}

bool ASMessageDispatcher::addObserver(ASEntity *pReceiver, const char* MsgID, SEL_CallFuncD callfunc)
{
	ASMessageObserver* pNewObserver = new ASMessageObserver(pReceiver,MsgID,callfunc);//pReceiver will be retain 
#ifdef ASDEBUG
	for (std::list<ASMessageObserver*>::iterator it = _Observers.begin();it != _Observers.end();it++)
	{
		ASMessageObserver* pObserver = *it;
		if (*pNewObserver==*pObserver)
		{
			ASAssert(0,"ASMessageDispatcher::addObserver the observer already exist");
			return false;
		}
	}
#endif
	pReceiver->_SignalDestory.disconnect(this);
	pReceiver->_SignalDestory.connect(this,&ASMessageDispatcher::removeMsgAndObserverByEntityObj);
	_Observers.push_back(pNewObserver);
	return true;
}
bool ASMessageDispatcher::removeObserver(ASEntity* pReceiver)
{
	bool retFlag = false;
	for (std::list<ASMessageObserver*>::iterator it = _Observers.begin();it != _Observers.end();it++)
	{
		ASMessageObserver* pObserver = *it;
		if (pReceiver==pObserver->getReceiver())
		{
			pObserver->setActive(false);
			retFlag = true;
		}
	}
	return retFlag;
}
bool ASMessageDispatcher::removeObserver(const char* MsgID)
{
	bool retFlag = false;
	unsigned long hashcode = AS_StrHash(MsgID);
	for (std::list<ASMessageObserver*>::iterator it = _Observers.begin();it != _Observers.end();it++)
	{
		ASMessageObserver* pObserver = *it;
		if (hashcode==pObserver->getMsgIDHash()&&pObserver->getMsgID().compare(MsgID)==0)
		{
			pObserver->setActive(false);
			retFlag = true;
		}
	}
	return retFlag;
}
void ASMessageDispatcher::removeAllObserver()
{
	for (std::list<ASMessageObserver*>::iterator it = _Observers.begin();it != _Observers.end();it++)
	{
		delete *it;
	}
	_Observers.clear();
}

void ASMessageDispatcher::removeAllMessage()
{
	for (std::list<ASMessage*>::iterator it = _Msgs.begin();it != _Msgs.end();it++)
	{
		delete *it;
	}
	_Msgs.clear();
}

void ASMessageDispatcher::removeMessageRelatedEntity(ASEntity* entity)
{
	for (std::list<ASMessage*>::iterator it = _Msgs.begin();it != _Msgs.end();it++)
	{
		ASMessage* pASMsg = *it;
		if (pASMsg->getReceiver()==entity||pASMsg->getSender()==entity)
		{
			pASMsg->setActive(false);
		}
	}
}

void ASMessageDispatcher::removeMsgAndObserverByEntityObj(ASObject* pEntity)
{
	removeObserver((ASEntity*)pEntity);
	removeMessageRelatedEntity((ASEntity*)pEntity);
	pEntity->_SignalDestory.disconnect(this);
	ASLog("ASMessageDispatcher::removeMsgAndObserverByEntityObj ASEntity:%x,ID:%d",pEntity,pEntity->getASObjectID());
}

void ASMessageDispatcher::clear()
{
	removeAllMessage();
	removeAllObserver();
}

void ASMessageDispatcher::dispatchMessage(const char* MsgID,ASEntity* pSender,ASEntity* pReceiver,float fDelayTime,int nExtraData,void* pExtraInfo)
{
	dispatchMessage(ASMessage(MsgID,pSender,pReceiver,fDelayTime,nExtraData,pExtraInfo));
}
void ASMessageDispatcher::dispatchMessage(const ASMessage& msg)
{
	if (!msg.getActive())
	{
		return;
	}
	if (msg._fDelayTime>0)
	{
		_Msgs.push_back(new ASMessage(msg));
		if (msg.getReceiver())
		{
			msg.getReceiver()->_SignalDestory.disconnect(this);
			msg.getReceiver()->_SignalDestory.connect(this,&ASMessageDispatcher::removeMsgAndObserverByEntityObj);
		}
		if (msg.getSender())
		{
			msg.getSender()->_SignalDestory.disconnect(this);
			msg.getSender()->_SignalDestory.connect(this,&ASMessageDispatcher::removeMsgAndObserverByEntityObj);
		}
	}
	else
	{
		ASEntity* pReceiver = msg.getReceiver();
		if (pReceiver)
		{
			if (pReceiver->getActive())
			{
				pReceiver->onHandleMessage((void*)&msg);
			}
		}
		else
		{
			for (std::list<ASMessageObserver*>::iterator it = _Observers.begin();it != _Observers.end();it++)
			{
				ASMessageObserver* pObserver = *it;
				if (pObserver&&pObserver->getMsgIDHash()==msg.getMsgIDHash()&&pObserver->getMsgID()==msg.getMsgID())
				{
					pObserver->onHandleMessage((void*)&msg);
				}
			}
		}
	}
}
void ASMessageDispatcher::update(float dt)
{
	for (std::list<ASMessage*>::iterator it = _Msgs.begin();it != _Msgs.end();it++)
	{
		ASMessage* pASMsg = *it;
		pASMsg->_fDelayTime-=dt;
		if (pASMsg->_fDelayTime<=0.0f)
		{
			dispatchMessage(*pASMsg);
			pASMsg->setActive(false);
		}
	}
	for (std::list<ASMessage*>::iterator it = _Msgs.begin();it != _Msgs.end();)
	{
		if (!(*it)->getActive())
		{
			delete *it;
			it = _Msgs.erase(it);
		}
		else
		{
			it++;
		}
	}
	for (std::list<ASMessageObserver*>::iterator it = _Observers.begin();it != _Observers.end();)
	{
		ASMessageObserver* pObserver = *it;
		if (!(*it)->getActive())
		{
			delete pObserver;
			it = _Observers.erase(it);
		}
		else
		{
			it++;
		}
	}
}

NS_AS_END